﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.ComponentModel;
using System.Windows.Forms;
using System.Windows.Automation;

public enum WorkItemPriority
{
    High,
    Low
}

public class XItem : WorkItem
{
    public XItem(WorkQueue q, TreeView tv) : base(q)
    {
        this.treeView1 = tv;
    }
    public override void Execute()
    {
        ThreadStart t = delegate
        {
            AutomationElement el = TreeWalker.ControlViewWalker.GetFirstChild(AutomationElement.RootElement);


            treeView1.Nodes.Add(el.GetCurrentPropertyValue(AutomationElement.NameProperty, true).ToString());
            AutomationElement el1 = TreeWalker.ControlViewWalker.GetNextSibling(el);
            treeView1.Nodes.Add(el1.GetCurrentPropertyValue(AutomationElement.NameProperty, true).ToString());
            AutomationElement el2 = TreeWalker.ControlViewWalker.GetNextSibling(el);
            treeView1.Nodes.Add(el2.GetCurrentPropertyValue(AutomationElement.NameProperty, true).ToString());
            AutomationElement el3 = TreeWalker.ControlViewWalker.GetNextSibling(el);
            treeView1.Nodes.Add(el3.GetCurrentPropertyValue(AutomationElement.NameProperty, true).ToString());
            AutomationElement el4 = TreeWalker.ControlViewWalker.GetNextSibling(el);
            treeView1.Nodes.Add(el4.GetCurrentPropertyValue(AutomationElement.NameProperty, true).ToString());
        };
        treeView1.Invoke(t);

    }

    TreeView treeView1;
}
 
public abstract class WorkItem : IDisposable
{
    // Fields
    private WorkQueue _queue;

    // Methods
    protected WorkItem(WorkQueue queue)
    {
        this._queue = queue;
    }

    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        this._queue = null;
    }

    public abstract void Execute();

    // Properties
    protected WorkQueue Queue
    {
        get
        {
            return this._queue;
        }
    }
}



internal static class Validate
{
    // Methods
    internal static void ArgumentNotNull(object argument, string argumentName)
    {
        if (object.ReferenceEquals(argument, null))
        {
            throw new ArgumentNullException();
        }
    }
}

 

public class WorkQueue : IDisposable
{
    // Fields
    private bool _blocked;
    private List<WorkItem> _highPriQueue;
    private ThreadStart _initialization;
    private List<WorkItem> _lowPriQueue;
    private static TimeSpan _maximumWorkItemTime = new TimeSpan(0, 0, 1);
    private ManualResetEvent _resetEvent;
    private System.Threading.Timer _resilianceTimer;
    private bool _shutdown;
    private TimeSpan _timeSpan;
    private Thread _workerThread;

    // Events
    public event EventHandler Blocked;

    public event EventHandler Unblocked;

    public event EventHandler WorkCompleted;

    // Methods
    public WorkQueue()
    {
        this._highPriQueue = new List<WorkItem>();
        this._lowPriQueue = new List<WorkItem>();
        this._resetEvent = new ManualResetEvent(false);
        this._workerThread = new Thread(new ThreadStart(this.ThreadProcedure));
        this._workerThread.SetApartmentState(ApartmentState.STA);
        this._workerThread.Start();
        this._timeSpan = new TimeSpan(0, 0, 10);
    }

    public WorkQueue(ThreadStart initialization)
        : this()
    {
        Validate.ArgumentNotNull(initialization, "initialization");
        this._initialization = initialization;
    }

    public void AbortCurrentWorkItem()
    {
        this._workerThread.Abort();
        this._workerThread = new Thread(new ThreadStart(this.ThreadProcedure));
        this._workerThread.Start();
    }

    public void Dispose()
    {
        this.Dispose(true);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            this._resilianceTimer.Dispose();
            this._shutdown = true;
            this._resetEvent.Set();
            this._workerThread.Join(this._timeSpan);
            this._resetEvent.Close();
        }
        this._resilianceTimer = null;
        this._resetEvent = null;
        this._workerThread = null;
    }

    public void Enqueue(WorkItem item)
    {
        this.Enqueue(item, WorkItemPriority.High);
    }

    public void Enqueue(WorkItem item, WorkItemPriority priority)
    {
        List<WorkItem> targetQueue;
        Validate.ArgumentNotNull(item, "item");
        if (priority == WorkItemPriority.High)
        {
            targetQueue = this._highPriQueue;
        }
        else
        {
            if (priority != WorkItemPriority.Low)
            {
                throw new ArgumentException("No known WorkItemPriority", "priority");
            }
            targetQueue = this._lowPriQueue;
        }
        lock (targetQueue)
        {
            targetQueue.Add(item);
        }
        this._resetEvent.Set();
    }

    private void Execute(WorkItem workItem)
    {
        Validate.ArgumentNotNull(workItem, "workItem");
        try
        {
            this._blocked = false;
            this._resilianceTimer.Change((int)_maximumWorkItemTime.TotalMilliseconds, -1);
            workItem.Execute();
        }
        catch (Win32Exception ex)
        {
            //Trace.WriteLine("Exception! " + ex.ToString());
        }
        catch (Exception ex)
        {
            //Trace.WriteLine("Exception! " + ex.ToString());
        }
        finally
        {
            this._resilianceTimer.Change(-1, -1);
            if (this._blocked)
            {
                this._blocked = false;
                this.OnUnblocked(null);
            }
        }
    }

    protected virtual void OnBlocked(EventArgs e)
    {
        if (this.Blocked != null)
        {
            this.Blocked(this, e);
        }
    }

    protected virtual void OnUnblocked(EventArgs e)
    {
        if (this.Unblocked != null)
        {
            this.Unblocked(this, e);
        }
    }

    protected virtual void OnWorkComplete(EventArgs e)
    {
        if (this.WorkCompleted != null)
        {
            this.WorkCompleted(this, e);
        }
    }

    private void ThreadProcedure()
    {
        bool signalled = false;
        this._resilianceTimer = new System.Threading.Timer(new TimerCallback(this.WorkItemTimeout), null, -1, -1);
        if (this._initialization != null)
        {
            this._initialization();
        }
        while (!this._shutdown)
        {
            WorkItem item;
            while ((this._highPriQueue.Count != 0) && !this._shutdown)
            {
                lock (this._highPriQueue)
                {
                    item = this._highPriQueue[0];
                    this._highPriQueue.RemoveAt(0);
                }
                this._resetEvent.Reset();
                this.Execute(item);
            }
            if ((this._lowPriQueue.Count != 0) && !this._shutdown)
            {
                lock (this._lowPriQueue)
                {
                    item = this._lowPriQueue[0];
                    this._lowPriQueue.RemoveAt(0);
                }
                this.Execute(item);
            }
            else
            {
                if (signalled)
                {
                    this.OnWorkComplete(null);
                }
                signalled = this._resetEvent.WaitOne(this._timeSpan, false);
            }
        }
    }

    private void WorkItemTimeout(object status)
    {
        this._blocked = true;
        this.OnBlocked(null);
    }
}


